package cn.com.miao.lynx.common.core.util

import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.lang.reflect.Method
import java.lang.reflect.Modifier
import java.util.*

/**
 * @title: ReflectTool
 * @description:
 * @author: dengmiao
 * @create: 2019-11-25 09:27
 */
class ReflectTool private constructor(private val obj: Any) {

    private val cls: Class<*>
    private val getterMethods: MutableMap<String, Method>
    private val setterMethods: MutableMap<String, Method>

    /**
     * @param attr  对象的属性名
     * @param value 被赋予的值
     */
    fun setter(attr: String, value: Any?) {
        val setter = setterMethods[attr.toLowerCase()]
        if (setter == null) log.error("没有找到对应属性名的setter") else {
            val flag = setter.canAccess(obj)
            try {
                setter.isAccessible = true
                setter.invoke(obj, value)
            } catch (e: Exception) {
                log.error("设置属性值失败(可能是value类型不匹配)")
                e.printStackTrace()
            } finally {
                setter.isAccessible = flag
            }
        }
    }

    /**
     * @param attr      对象的属性名
     * @param valueType 属性值的类型
     */
    fun <T> getter(attr: String, valueType: Class<T>): T? {
        val getter = getterMethods[attr.toLowerCase()]
        var value: T? = null
        if (getter == null) log.error("没有找到对应属性名的getter(返回null)") else {
            val flag = getter.canAccess(obj)
            try {
                getter.isAccessible = true
                value = valueType.cast(getter.invoke(obj))
            } catch (e: ClassCastException) {
                e.printStackTrace()
                log.error("属性值的类型不正确(返回null)")
            } catch (e: Exception) {
                e.printStackTrace()
                log.error("获取属性值失败(返回null)")
            } finally {
                getter.isAccessible = flag
            }
        }
        return value
    }

    companion object {

        val log: Logger = LoggerFactory.getLogger(ReflectTool::class.java)

        @kotlin.jvm.JvmStatic
        fun reflectToolFactory(obj: Any): ReflectTool {
            return ReflectTool(obj)
        }
    }

    init {
        cls = obj.javaClass
        getterMethods = HashMap()
        setterMethods = HashMap()
        //获取方法集
        val methods = cls.declaredMethods
        val setterRegex = "^set[a-zA-Z_$0-9]+".toRegex()
        val getterRegex = "^get[a-zA-Z_$0-9]+".toRegex()
        //初始化getter与setter方法集
        for (x in methods) {
            val modifiers = x.modifiers
            val isStatic = Modifier.isStatic(modifiers)
            val isFinal = Modifier.isFinal(modifiers)
            // 排除static或final修饰的方法
            if (isStatic || isFinal) {
                continue
            }
            val flag = x.canAccess(obj)
            x.isAccessible = true
            val methodName = x.name.toLowerCase()
            if (methodName.matches(setterRegex)) {
                val attrName = methodName.replaceFirst("set".toRegex(), "")
                setterMethods[attrName] = x
            } else if (methodName.matches(getterRegex)) {
                val attrName = methodName.replaceFirst("get".toRegex(), "")
                getterMethods[attrName] = x
            }
            x.isAccessible = flag
        }
    }
}
